Перейти к основному содержимому

5.08. Философия языка

Разработчику Архитектору

Философия языка

Что такое объект - мы помним. Мы рассматривали его с точки зрения современных концепций, как Java, но всё же принцип «всё есть объект» понять несложно. Даже самые базовые сущности в Smalltalk являются обхектами.

К примеру, 1234 будет объектом класса Integer, у которого есть метод factorial.

true и false - объекты, отвечающие на сообщения ifTrue, ifFalse.

nil (аналог null) тоже объект, единственный экземпляр класса UndefinedObject (неопределенный объект).

Классы - объекты, экземпляры метаклассов. Методы - объекты. Блоки кода - объекты, которые тоже можно передавать, хранить, вызывать. То есть, в системе нет «второсортных сущностей», и всё подчиняется единой модели.

Почему мы так акцентируем на этом? Понятнее станет, если рассмотреть другие языки.

В Java, например, не всё объект, допустим int и boolean - это примитивы. В C#, int - это структура, но не объект в полном смысле. В Python есть определенные «оптимизации», а в JavaScript примитивы не всегда ведут себя как объекты при доступе к методам. Словом, везде есть «но». Smalltalk же доводит идею до абсолюта: нет никакого разделения между данными и поведением, между типами и объектами.

Единственный способ взаимодействия - это посылка сообщений. Мы как-то изучали уже термин «вызов» функции или метода. То есть мы говорим «объект.метод()». В Smalltalk немного иначе - здесь мы посылаем сообщение в объект. Тут есть фундаментальная разница в модели вычислений - сообщение не привязано к классу, оно отправляется объекту, т.е. оно независимое. А объект же сам решает, как ответить. Если объект не понимает сообщение — он получает doesNotUnderstand:, и может динамически среагировать (например, делегировать, создать метод на лету, выбросить ошибку).

Пример - условие без операторов:

(x > 0) ifTrue: [ 'positive' ] ifFalse: [ 'negative' ]

Что здесь происходит?

  • (x > 0) возвращает true или false — объект.
  • Мы посылаем ему сообщение ifTrue:ifFalse:.
  • true и false реализуют это сообщение по-разному.

Как видим, какого-то ветвления в синтаксисе нет, есть лишь поведение объектов.

В Smalltalk нет аннотаций типов. Никаких String name, List<int>. Тип является свойством объекта, а не переменной:

| x |
x := 42.
x := 'hello'.
x := [ 1 + 2 ].

Но ошибки обнаруживаются только во время выполнения, и сложно порой понять, что ожидает метод, и как следствие - труднее оптимизировать. В других языках мы пишем код в редакторе, сохраняем в файл, запускаем компилятор, запускаем программу, при ошибках читаем логи, исправляем, перезапускаем.

В ST же мы погружаемся в работающую систему, где код - это объекты в памяти, и изменяя класс, мы немедленно меняем поведение ситемы. Словом, отладчик не является внешним инструментов, а своего рода «окно» в текущее состояние выполнения. Это как если бы вы могли изменить скрипт на веб-странице прямо в браузере — и изменения вступили в силу мгновенно, без перезагрузки.

А IDE в Smalltalk — не программа для написания кода. Это сама программа.

Необычно, правда?

Smalltalk — один из первых языков с полной рефлексией:

  • Любой объект может сказать: «Кто мой класс?» (obj class)
  • Любой класс может вернуть список своих методов (MyClass methods)
  • Можно добавить метод в класс на лету:
String compile: 'reverseUppercase ^ self reversed asUppercase'
  • Можно перехватить неизвестные сообщения:
doesNotUnderstand: aMessage
^ 'I don''t know ', aMessage selector

Многие практики современного программирования родились в этой экосистеме.

К примеру, рефакторинг - этот термин популяризирован Кентом Беком, который работал на Smalltalk. А также юнит-тестирование (SUnit), первый фреймворк для модульного тестирования, создан в Smalltalk (прообраз JUnit, NUnit). И конечно же экстремальное программирование, Extreme Programming (XP) — Кент Бек разработал его, используя Smalltalk и SUnit.

А теперь о минусах.

Как можно понять, есть обратная сторона, связанная с теми же особенностями. Например, проблемы безопасности. Полная рефлексия и возможность модификации системы на лету — риск, ведь любой код может изменить любой класс, а вредоносный скрипт может переписать что угодно. Это делает Smalltalk непригодным для систем с высокими требованиями к безопасности. Собственно современные языки в первую очередь потому и «живы» - из-за своей безопасности.

Далее - производительность. Интерпретируемый байт-код, паузы при автоматической сборке мусора, большое количество объектов - на практике всё это не подходит для высоконагруженных систем.

И конечно, дизайн. Отсутствие жёсткой структуры приводит к хаосу, и легко создавать магию (внезапно появляющиеся методы, перехват сообщений), и без дисциплины вся система станет непредсказуемой. Через неделю даже сам программист может не разобраться в своём же коде. Всё это не делает язык идеальным. Скорее полезным с точки зрения идеи и философии, учить думать иначе.

Можно встретить такие выражения, как «пуристская теория», которая как раз и подразумевает модель мышления, в которой программированием является не управлеине процессором, а организация диалога между объектами. Вы не пишете инструкции — вы создаёте среду, в которой объекты общаются. Вы не вызываете функции — вы посылаете сообщения.

И суть в том, что мир состоит из изолированных сущностей (объектов), между которыми есть один единственный способ взаимодействия - посылка сообщений. И поведение делегируется, объект сам решает, как ответить. В реальной жизни всё так же - вы не управляете человеком, вы просите его что-то сделать, он может сказать «да», «нет», проигнорировать или ответить как-то ещё, вы не лезете внутрь его головы и не переписываете его мышление. Это и есть чистое ООП. И сообщение не будет гарантировать, что объект его поймёт, выполнит его так, как вы ожидаете, и он вообще ответит. Можно встретить забавный пример, если написать:

bird fly

Если bird - это Sparrow (попугай), то полетит. Если Penguin (пингвин), он получит сообщение, но ответит иначе:

fly
self inform: 'I can''t fly!'

Если bird — это Rock, он получит doesNotUnderstand: #fly — и можно перехватить.

Смысл уловили? Сообщение — это предложение.

В итоге у нас нет жёсткой связи между отправителем и получателем, и вы не знаете как ответит объект, что делает его изолированным субъектом со своим внутренним состоянием, реакцией.

Такие дела. Поэтому не ругайтесь с пуристами и не убеждайте, что какой-то язык настоящее ООП, кроме ST.